package core

import (
	"errors"
	"fmt"
	"os"
	"runtime"
	"strconv"
	"strings"
	"syscall"

	"github.com/CIPFZ/collector/internal/app"
	"github.com/CIPFZ/collector/internal/types"
	"github.com/CIPFZ/collector/internal/vars"
	"github.com/CIPFZ/collector/pkg/exception"

	"go.uber.org/zap"
)

// CancelTaskWithPID 取消任务
func CancelTaskWithPID(collect *app.Collector, options *types.CancelOptions) error {
	logger := collect.Logger()
	pidFile := fmt.Sprintf(vars.TaskPIDFilePath, options.TaskID)

	// 读取 PID 文件
	data, err := os.ReadFile(pidFile)
	if err != nil {
		if errors.Is(err, os.ErrNotExist) {
			logger.Info("Task is not running (PID file missing)",
				zap.String("task-id", options.TaskID))
			return nil
		}
		return exception.WrapFileError(err, "read", pidFile)
	}

	// 解析 PID
	pidStr := strings.TrimSpace(string(data))
	pid, err := strconv.Atoi(pidStr)
	if err != nil {
		logger.Warn("Failed to convert PID file to int",
			zap.String("task-id", options.TaskID), zap.String("data", pidStr))
		return exception.NewInvalidPIDError(pidFile)
	}

	// 查找进程
	process, err := os.FindProcess(pid)
	if err != nil {
		logger.Warn("Failed to find process",
			zap.Int("pid", pid), zap.Error(err))
		return exception.NewTaskNotFoundError(options.TaskID)
	}

	// 发送终止信号
	var cancelErr error
	if runtime.GOOS == "windows" {
		if options.Force {
			cancelErr = process.Kill()
			logger.Info("Force kill sent to task",
				zap.String("task-id", options.TaskID), zap.Int("pid", pid))
		} else {
			cancelErr = process.Signal(os.Interrupt)
			logger.Info("Termination signal sent to task",
				zap.String("task-id", options.TaskID), zap.Int("pid", pid))
		}
	} else {
		if options.Force {
			cancelErr = process.Signal(syscall.SIGKILL)
			logger.Info("Force kill sent to task",
				zap.String("task-id", options.TaskID), zap.Int("pid", pid))
		} else {
			cancelErr = process.Signal(syscall.SIGTERM)
			logger.Info("Termination signal sent to task",
				zap.String("task-id", options.TaskID), zap.Int("pid", pid))
		}
	}

	if cancelErr != nil {
		logger.Error("Failed to cancel task", zap.Error(cancelErr))
		return exception.NewTaskCancelError(options.TaskID, cancelErr)
	}

	// 删除 PID 文件并记录失败日志
	if removeErr := os.Remove(pidFile); removeErr != nil && !errors.Is(removeErr, os.ErrNotExist) {
		logger.Warn("Failed to remove PID file",
			zap.String("task-id", options.TaskID),
			zap.String("file", pidFile),
			zap.Error(removeErr))
	}

	conf := collect.Config()
	// 删除对应 id 的收集任务状态文件
	taskStatusManager := NewTaskStatusManager(conf.Output.Dir, false)
	if err = taskStatusManager.RemoveTaskStatusFile(options.TaskID); err != nil {
		logger.Warn("Failed to remove task status file",
			zap.String("task-id", options.TaskID),
			zap.Error(err))
	}
	// 删除对应 id 的收集残留信息

	return nil
}
